﻿using System;
using System.Text;
using System.IO;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Collections.Generic;
using System.Data;
using System.Windows.Data;
using System.Windows.Documents;

using log4net;
using System.Reflection;

namespace proyecto
{
    class R_Script
    {
        private static readonly ILog log = LogManager.GetLogger(typeof(R_Script));

        [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
        private static extern Int32 GetShortPathName(String lpszLongPath, StringBuilder lpszShortPath, Int32 cchBuffer);
        private DataTable matrix;
        private List<string> libraries;
        private string output;
        private string outError;
        private String outputDataSource;
        private List<string> lstTempFiles = new List<string>();
        public static string noRMessage = "No R Installed";

        public R_Script(DataTable doc)
        {

            this.libraries = new List<string>();
            this.output = null;
            this.outError = null;
            this.outputDataSource = null;
            this.matrix = doc.Clone();

            for (int i = 0; i < doc.Rows.Count; i++)
            {
                DataRow row = matrix.NewRow();

                for (int j = 0; j < doc.Columns.Count; j++)
                    row[j] = doc.Rows[i][j];
                matrix.Rows.Add(row);
            }


        }


        private void execScript(FileInfo theFileInfo, string theScriptParams)
        {
            Process process = null;

            ProcessStartInfo startinfo = new ProcessStartInfo();

            string strCurAsmDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);

            string RScriptCmdLine = "";
            string R_PackageNameVersion = "R-2.12.0_*";
            DirectoryInfo[] folders = System.IO.Directory.GetParent(strCurAsmDir).GetDirectories(R_PackageNameVersion, SearchOption.TopDirectoryOnly);
            if (folders.Length == 1)
                RScriptCmdLine = "C:\\Program files\\R\\bin\\RScript.exe";

            //fix bug http://213.9.224.133:8080/bugzilla-2.18.1/show_bug.cgi?id=2223 begin
/*#if DEBUG

            string AssemblyName = "Integromics.WorkflowPackage.IBMD";
            foreach (Assembly asm in AppDomain.CurrentDomain.GetAssemblies())
            {
                if (asm.Location.Contains(AssemblyName))
                {
                    string strLocation = asm.Location.Substring(0, asm.Location.IndexOf(AssemblyName));
                    RScriptCmdLine = strLocation + Properties.Resources.DebugRScriptPath;
                    break;
                }
            }

#endif*/
           
            if (!File.Exists(RScriptCmdLine))
                throw new Exception(R_Script.noRMessage);

            startinfo.FileName = "\"" + RScriptCmdLine + "\"";
            startinfo.Arguments = "--vanilla " + GetShortPathName2(theFileInfo.FullName) + " " + theScriptParams;

            log.Debug(startinfo.FileName + " " + startinfo.Arguments);
            //Configure RScript execution 
            startinfo.UseShellExecute = false;
            startinfo.RedirectStandardOutput = true;
            startinfo.RedirectStandardError = true;
            startinfo.CreateNoWindow = true;

            process = Process.Start(startinfo);
            StreamReader stdout = process.StandardOutput;

            // Set our event handler to asynchronously read the rScript output.
            process.ErrorDataReceived += new DataReceivedEventHandler(R_ScriptErrorHandler);

            //Read Standard output asynchronously
            process.BeginErrorReadLine();

            //Read Standard Error synchronously
            this.output = stdout.ReadToEnd();
            string to_log = this.output.Substring(0, (this.output.Length > 1000) ? 1000 : this.output.Length);
            log.Debug("R script output\n" + to_log);
            stdout.Close();

            MemoryStream memStream =
                new MemoryStream(System.Text.Encoding.Default.GetBytes(this.output));

            //this.outputDataSource = new *****(memStream, null);

            if (process != null)
            {

                if (!process.HasExited)
                {
                    process.WaitForExit();
                    process.Close();
                }
                if (this.outError != null)
                {
                    //Begin Borislav: http://213.9.224.133:8080/bugzilla-2.18.1/show_bug.cgi?id=2387 
                    log.Error("R script execution failed: " + this.outError);
                    this.outError = this.outError.Substring(this.outError.LastIndexOf(":") + 2);
                    if (this.outError == "Flag")
                        this.outError = "There is no column with the name: Flag";
                    //End Borislav: http://213.9.224.133:8080/bugzilla-2.18.1/show_bug.cgi?id=2387 

                    throw new Exception(this.outError);
                }
            }//if process !=null

        }





        private void R_ScriptErrorHandler(object sendingProcess,
            DataReceivedEventArgs outLine)
        {
            // The error handler only process the error messages. The R error messages starts with "Error:" string
            if (!String.IsNullOrEmpty(outLine.Data))
            {

                if (outLine.Data.Contains("BiomarkerDiscovery Error"))
                {
                    if (!(sendingProcess as Process).HasExited)
                        (sendingProcess as Process).CancelErrorRead();

                    this.outError = outLine.Data;
                    log.Error(this.outError);

                }//if an Error was issued
                else //if a Warn was issued
                    log.Warn(this.outError);
            }//if error/warns is not null


        }

        private static String GetShortPathName(String longName)
        {
            Int32 max = longName.Length;
            StringBuilder sb = new StringBuilder(max);
            GetShortPathName(longName, sb, max);
            return sb.ToString();
        }

        private static String GetShortPathName2(String longName)
        {
            StringBuilder shortPath = new StringBuilder(255);
            GetShortPathName(longName, shortPath, shortPath.Capacity);
            return shortPath.ToString();
        }

        public string getOut()
        {
            return output;
        }
    }
}
